#ifndef AVALON_SERVICELOCATORCHANNEL_HPP
#define AVALON_SERVICELOCATORCHANNEL_HPP
#include <set>
#include <vector>
#include "Avalon/IO/Channel.hpp"
#include "Avalon/ServiceLocator/AuthenticatedServerChannel.hpp"
#include "Avalon/Services/ServiceProtocolServerChannel.hpp"

namespace Avalon {
namespace ServiceLocator {

  /*! \class ServiceLocatorChannel
   *  \brief A Channel used by the ServiceLocatorServlet to represent a client.
   */
  class ServiceLocatorChannel : public IO::Channel,
      private Services::ServiceProtocolServerChannel,
      private AuthenticatedServerChannel {
    public:

      //! Constructs a ServiceLocatorChannel.
      /*!
        \param channel The existing Channel to the client.
      */
      ServiceLocatorChannel(IO::Channel* channel);

      virtual ~ServiceLocatorChannel();

      //! Returns the session id.
      const std::string& GetSessionId() const;

      //! Sets the session id.
      void SetSessionId(const std::string& sessionId);

      //! Returns the DirectoryEntry subscriptions.
      const std::set<DirectoryEntry::Tag>& GetDirectoryEntrySubscriptions()
        const;

      //! Adds a DirectoryEntry subscription.
      /*!
        \param tag The Tag of the DirectoryEntry to subscribe to.
      */
      void AddDirectoryEntrySubscription(const DirectoryEntry::Tag& tag);

      //! Removes a DirectoryEntry subscription.
      /*!
        \param tag The Tag of the DirectoryEntry to unsubscribe from.
      */
      void RemoveDirectoryEntrySubscription(const DirectoryEntry::Tag& tag);

      //! Returns the services being subscribed to by this Channel.
      const std::vector<std::string>& GetServiceSubscriptions() const;

      //! Subscribes to a service.
      /*!
        \param serviceName The name of the service to subscribe to.
      */
      void SubscribeService(const std::string& serviceName);

      //! Unsubscribes from a service.
      /*!
        \param serviceName The name of the service to unsubscribe from.
      */
      void UnsubscribeService(const std::string& serviceName);

      //! Returns the ServiceEntries registered by this Channel.
      const std::vector<ServiceEntry>& GetRegisteredServices() const;

      //! Registers a service.
      /*!
        \param serviceEntry The ServiceEntry describing the registered service.
      */
      void RegisterService(const ServiceEntry& serviceEntry);

      //! Unregisters a service id.
      /*!
        \param serviceId The id of the service unregister.
      */
      void UnregisterService(int serviceId);

      virtual IO::Connection& GetConnection();

      virtual IO::Reader& GetReader();

      virtual IO::Writer& GetWriter();

      using ServiceProtocolServerChannel::GetConnectionState;
      using ServiceProtocolServerChannel::GetTaskQueue;
      using ServiceProtocolServerChannel::GetLastTaskResult;
      using ServiceProtocolServerChannel::GetServiceProtocol;
      using ServiceProtocolServerChannel::SendMessage;
      using AuthenticatedServerChannel::GetAccount;
      using AuthenticatedServerChannel::IsLoggedIn;
      using AuthenticatedServerChannel::ResetAccount;
      using AuthenticatedServerChannel::SetAccount;

    private:
      boost::scoped_ptr<IO::Channel> m_channel;
      std::string m_sessionId;
      std::vector<ServiceEntry> m_registeredServices;
      std::vector<std::string> m_serviceSubscriptions;
      std::set<DirectoryEntry::Tag> m_directoryEntrySubscriptions;
  };
}
}

#endif // AVALON_SERVICELOCATORCHANNEL_HPP
